﻿Imports System.Security.Cryptography
Imports myBookmarks.Core
Imports myBookmarks.Data
Namespace myBookmarks.Infrastructure
    Public Class UserService
        Implements IUserService
        Private _userRepository As IUserRepository
        Public Sub New(ByVal userrepository As IUserRepository)
            _userRepository = userrepository
        End Sub
        Public Function GetUserByUsername(ByVal username As String) As User Implements IUserService.GetUserByUsername
            Return _userRepository.GetByUsername(username)
        End Function
        Public Function CreateUser(ByVal username As String, ByVal password As String) As User Implements IUserService.CreateUser
            Dim user As New User With {.UserId = Guid.NewGuid(), .CreatedDate = DateTime.Now, .LastVisited = DateTime.Now}
            user.Email = username
            user.UserName = username
            user.PasswordSalt = CreateSalt()
            user.PasswordHash = GetPasswordHash(password, user.PasswordSalt)
            _userRepository.CreateUser(user)
            Return user
        End Function
        Public Function SaveUser(ByVal user As User) As Boolean Implements IUserService.SaveUser
            Return _userRepository.SaveUser(user)
        End Function

        Public Function ChangePassword(ByVal user As User, ByVal newpassword As String) As Boolean Implements IUserService.ChangePassword
            Dim passwordsalt As String = CreateSalt()
            Dim passwordhash As String = GetPasswordHash(newpassword, passwordsalt)
            user.PasswordSalt = passwordsalt
            user.PasswordHash = passwordhash
            Return SaveUser(user)
        End Function
        Public Function DoesUsernameExists(ByVal username As String) As Boolean Implements IUserService.DoesUsernameExists
            Dim user As User = _userRepository.GetByUsername(username)
            If user Is Nothing Then
                Return False
            End If
            Return True
        End Function
        Public Function ValidateUser(ByVal user As User, ByVal password As String) As Boolean Implements IUserService.ValidateUser
            If user Is Nothing Then
                Return False
            End If
            Dim passwordHash As String = GetPasswordHash(password, user.PasswordSalt)
            Return passwordHash.Equals(user.PasswordHash)
        End Function

        ''' <summary>
        ''' Create salt for encrypting user passwords.  
        ''' Original Source: http://davidhayden.com/blog/dave/archive/2004/02/16/157.aspx
        ''' </summary>
        ''' <returns></returns>
        Public Function CreateSalt() As String
            Dim size As Integer = 64
            'Generate a cryptographic random number.
            Dim rng = New RNGCryptoServiceProvider()
            Dim buff = New Byte(size - 1) {}
            rng.GetBytes(buff)

            ' Return a Base64 string representation of the random number.
            Return Convert.ToBase64String(buff)
        End Function

        ''' <summary>
        ''' Create a password hash based on a password and salt.  
        ''' Adapted from: http://davidhayden.com/blog/dave/archive/2004/02/16/157.aspx
        ''' </summary>
        ''' <returns></returns>
        Public Function ComputeHash(ByVal valueToHash As String) As String
            Dim algorithm As HashAlgorithm = SHA512.Create()
            Dim hash As Byte() = algorithm.ComputeHash(Encoding.UTF8.GetBytes(valueToHash))

            Return Convert.ToBase64String(hash)
        End Function

        Public Function GetPasswordHash(ByVal password As String, ByVal salt As String) As String
            Return ComputeHash(password + salt)
        End Function

    End Class
End Namespace